package com.zc.wxPay.controller;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.thoughtworks.xstream.XStream;
import com.zc.custom.domain.ChargeCustomOrderInfo;
import com.zc.custom.domain.ChargeCustomUser;
import com.zc.custom.mapper.ChargeCustomOrderInfoMapper;
import com.zc.custom.mapper.ChargeCustomOrderInvoiceMapper;
import com.zc.custom.mapper.ChargeCustomUserMapper;
import com.zc.iotDevice.domain.IotDeviceSubsidiary;
import com.zc.iotDevice.domain.IotDeviceSubsidiaryPort;
import com.zc.iotDevice.mapper.IotDeviceSubsidiaryMapper;
import com.zc.operator.domain.ChargeMchInfo;
import com.zc.operator.domain.ChargeStation;
import com.zc.operator.mapper.ChargeMchInfoMapper;
import com.zc.operator.mapper.ChargeStationMapper;
import com.zc.wxPay.domain.WxPay;
import com.zc.wxPay.entity.*;
import com.zc.wxPay.service.WXPayService;
import com.zc.wxPay.util.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.security.Security;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author gaojikun
 * @Description 微信支付相关接口
 */
@RestController
@RequestMapping(value = "/api/wxPay")
public class WXPayController {

    @Autowired
    private WXPayService wXPayService;

    @Autowired
    private ChargeCustomOrderInfoMapper chargeCustomOrderInfoMapper;

    @Autowired
    private IotDeviceSubsidiaryMapper iotDeviceSubsidiaryMapper;

    @Autowired
    private ChargeCustomUserMapper chargeCustomUserMapper;

    @Autowired
    private ChargeStationMapper chargeStationMapper;

    @Autowired
    private ChargeMchInfoMapper chargeMchInfoMapper;


    /**
     * 下单
     */
    @PostMapping("/payment")
    public WxPay payment(@RequestBody WxPay wxpay) {
        return wXPayService.payment(wxpay);
    }

    /**
     * 微信小程序支付成功回调函数
     */
    @RequestMapping(value = "/callback")
    @Transactional
    public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
//        System.out.println("微信统一下单回调：接收到的报文==========>" + notityXml);

        Map map = PayUtil.doXMLParse(notityXml);

        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
            String validStr = PayUtil.createLinkString(validParams);//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            //根据商户订单号查询
            ChargeCustomOrderInfo orderInfo = chargeCustomOrderInfoMapper.selectChargeCustomOrderInfoByOrderInfoCode(map.get("out_trade_no").toString());
            //查询场站信息
            ChargeStation chargeStation = chargeStationMapper.selectChargeStationByChargeStationCode(orderInfo.getChargeStationCode());
            String sign = PayUtil.sign(validStr, chargeStation.getMchKey(), "utf-8").toUpperCase();//拼装生成服务器端验证的签名

            // 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了
            if ("1".equals(orderInfo.getOrderInfoStatus())) {
                System.out.println("微信统一下单回调：微信支付回调已结束，跳过当次回调");
                //通知微信服务器已经支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
                return;

            }

            if (sign.equals(map.get("sign")) && (orderInfo.getTotalMoney().multiply(new BigDecimal("100"))).compareTo(new BigDecimal(map.get("cash_fee").toString())) == 0) {
                BigDecimal cash_fee = new BigDecimal(map.get("cash_fee").toString()).divide(new BigDecimal("100"));
                //账户余额变动
//                ChargeCustomUser chargeCustomUser = chargeCustomUserMapper.selectChargeCustomUserByOpenid(orderInfo.getCustomCode());
//                chargeCustomUser.setAvailableBalance(chargeCustomUser.getAvailableBalance().add(cash_fee));
//                int i = chargeCustomUserMapper.updateChargeCustomUser(chargeCustomUser);
//                if (i != 1) {
//                    System.out.println("微信支付回调逻辑出现问题，用户账户余额变动失败");
//                    return;
//                }

                //修改订单状态为已支付
                orderInfo.setOrderInfoStatus("1");
                orderInfo.setPaymentAmount(cash_fee);
                orderInfo.setTransactionId(map.get("transaction_id").toString());
                orderInfo.setPayTime(DateUtils.getNowDate());
                int i = chargeCustomOrderInfoMapper.updateChargeCustomOrderInfo(orderInfo);
                if (i != 1) {
                    System.out.println("微信支付回调逻辑出现问题，修改订单状态为已支付失败");
                    return;
                }

                //修改设备端口为使用中
                IotDeviceSubsidiaryPort port = new IotDeviceSubsidiaryPort(Long.parseLong(orderInfo.getPortId()), "2");
                iotDeviceSubsidiaryMapper.updateSubsidiaryPort(port);


                //通知微信服务器已经支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                System.out.println("微信统一下单回调：微信支付回调失败!签名不一致");
            }
            //根据微信官网的介绍，此处不仅对回调的参数进行验签，还需要对返回的金额与系统订单的金额进行比对等
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
//        System.out.println("微信统一下单回调：resXml===========>"+resXml);
        System.out.println("微信统一下单回调：微信支付回调数据结束");

        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }

    /**
     * 查询订单  未使用
     */
    @PostMapping("/orderQuery")
    @Transactional
    public WxPay orderQuery(@RequestBody WxPay wxpay) {

        try {

            //根据商户订单号查询
            ChargeCustomOrderInfo orderInfo = chargeCustomOrderInfoMapper.selectChargeCustomOrderInfoByOrderInfoCode(wxpay.getOutTradeNo());
            //查询场站信息
            ChargeStation chargeStation = chargeStationMapper.selectChargeStationByChargeStationCode(orderInfo.getChargeStationCode());

            OrderQueryInfo order = new OrderQueryInfo();
            order.setAppid(Configure.getAppID());
            order.setMch_id(chargeStation.getMchId());
            order.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
            order.setOut_trade_no(wxpay.getOutTradeNo());
            //order.setSign_type("MD5");
            //生成签名
            String sign = Signature.getSign(order,chargeStation.getMchKey());
            order.setSign(sign);

            String result = HttpRequest.sendPost(Configure.getQuery_url(), order);
            System.out.println(result);

            XStream xStream = new XStream();
            xStream.alias("xml", QueryReturnInfo.class);
            xStream.ignoreUnknownElements();
            Class<?>[] classes = new Class[]{QueryReturnInfo.class};
            xStream.allowTypes(classes);
            Object preOrderResult = xStream.fromXML(result);
            ObjectMapper objectMapper = new ObjectMapper();
            QueryReturnInfo returnInfo = objectMapper.convertValue(preOrderResult, QueryReturnInfo.class);

            //逻辑处理
//            SUCCESS--支付成功
//            REFUND--转入退款
//            NOTPAY--未支付
//            CLOSED--已关闭
//            REVOKED--已撤销(刷卡支付)
//            USERPAYING--用户支付中
//            PAYERROR--支付失败(其他原因，如银行返回失败)
//            ACCEPT--已接收，等待扣款
            String tradeState = returnInfo.getTrade_state();//付款窗台
            int total_fee = returnInfo.getTotal_fee();//订单总金额，单位为分
            String time_end = returnInfo.getTime_end();//订单支付时间，格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则

            wxpay.setStatus(200);
            wxpay.setMsg("查询订单成功!");
            wxpay.setData(null);
            return wxpay;
        } catch (Exception e) {
            e.printStackTrace();
//            System.out.println("微信订单查询：发生异常==============》" + e);
            wxpay.setStatus(500);
            wxpay.setMsg("查询订单失败!");
            return wxpay;
        }
    }


    /**
     * 关闭订单
     */
    @PostMapping("/closeOrder")
    public WxPay closeOrder(@RequestBody WxPay wxpay) {
        return wXPayService.closeOrder(wxpay);
    }


    /**
     * 取消支付
     */
    @PostMapping("/disDeal")
    public WxPay disDeal(@RequestBody WxPay wxpay) {
        return wXPayService.disDeal(wxpay);
    }


    /**
     * 申请退款
     */
    @PostMapping("/refund")
    public WxPay refund(@RequestBody WxPay wxpay) {
        return wXPayService.refund(wxpay);
    }

    /**
     * 申请退款成功回调函数
     */
    @RequestMapping(value = "/refundCallback")
    @Transactional
    public void refundCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
//        System.out.println("微信统一下单回调：接收到的报文==========>" + notityXml);

        Map map = PayUtil.doXMLParse(notityXml);

        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
//            //验证签名是否正确
//            Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
//            String validStr = PayUtil.createLinkString(validParams);//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
//            String sign = PayUtil.sign(validStr, chargeMchInfo.getMchKey(), "utf-8").toUpperCase();//拼装生成服务器端验证的签名

            //获取商户key
            String mch_id = (String) map.get("mch_id");
            ChargeMchInfo chargeMchInfo = chargeMchInfoMapper.selectChargeMchInfoByMchId(mch_id);

            //退款回调解密信息
            String req_info = (String) map.get("req_info");
            Security.addProvider(new BouncyCastleProvider());
            sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
            byte[] bt = decoder.decodeBuffer(req_info);
//            String b = new String(bt);
            String md5key = MD5.MD5(chargeMchInfo.getMchKey()).toLowerCase();
            SecretKey secretKey = new SecretKeySpec(md5key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] resultbt = cipher.doFinal(bt);
            String req_info_xml_string = new String(resultbt, "UTF-8");

            System.out.println("微信退款结果通知解密后请求数据xml:" + req_info_xml_string);
            if (!StringUtils.isEmpty(req_info_xml_string)) {
                //添加对应的业务逻辑
                Map req_info_map = PayUtil.doXMLParse(req_info_xml_string);

                //根据商户订单号查询
                ChargeCustomOrderInfo orderInfo = chargeCustomOrderInfoMapper.selectChargeCustomOrderInfoByOrderInfoCode(req_info_map.get("out_trade_no").toString());
                // 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了
                if ("5".equals(orderInfo.getOrderInfoStatus())) {
                    System.out.println("微信退款结果通知：微信退款结果通知已结束，跳过当次回调");
                    //通知微信服务器已经支付成功
                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                    out.write(resXml.getBytes());
                    out.flush();
                    out.close();
                    return;

                }
                //修改订单状态为已退款
                orderInfo.setOrderInfoStatus("5");
                orderInfo.setOrderStatus("2");
                BigDecimal settlement_refund_fee = new BigDecimal(req_info_map.get("settlement_refund_fee").toString()).divide(new BigDecimal("100"));
                System.out.println("————————————————————————————微信支付退款回调————————————————————————————>" + orderInfo.getRefundAmount());
                System.out.println("————————————————————————————微信支付退款回调————————————————————————————>" + settlement_refund_fee);
//                System.out.println("————————————————————————————微信支付退款回调————————————————————————————>" + orderInfo.getRefundAmount().add(settlement_refund_fee));
//                orderInfo.setRefundAmount(orderInfo.getRefundAmount().add(settlement_refund_fee));
                orderInfo.setRefundTime(DateUtils.getNowDate());
                chargeCustomOrderInfoMapper.updateChargeCustomOrderInfo(orderInfo);

                //修改账户可用余额
//                ChargeCustomUser chargeCustomUser = chargeCustomUserMapper.selectChargeCustomUserByOpenid(orderInfo.getCustomCode());
//                chargeCustomUser.setAvailableBalance(chargeCustomUser.getAvailableBalance().subtract(settlement_refund_fee));
//                int i = chargeCustomUserMapper.updateChargeCustomUser(chargeCustomUser);


                //通知微信服务器已经支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                //解密失败
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        System.out.println("微信统一下单回调：微信支付回调数据结束");

        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }


    /**
     * 查询退款 退款有一定延时，用零钱支付的退款20分钟内到账，银行卡支付的退款3个工作日后重新查询退款状态。
     */
    @PostMapping("/refundQuery")
    public WxPay refundQuery(@RequestBody WxPay wxpay) {
        return wXPayService.refundQuery(wxpay);
    }

}
